#ifndef BeforeCallTask_h
#define BeforeCallTask_h
#include "task.h"
#include "../abc_commons.h"

using namespace abc;

namespace task
{
    struct ImportDescriptorContext
    {
    };

    class BeforeCallTask : public TransformTask
    {
        using TransformTask::TransformTask;
        bool analyze(InstStructType instStruct) override
        {
            auto *inst = getAs<AbckitInst>(instStruct);
            if (!inst)
            {
                return false;
            }
            // 先分析import是否引入callSite，使用私有变量存储importDesc
            auto callSite = getAs<BasicApiInfo>(*this->param_->callSite);
            if (!this->containsImport(callSite->objName))
            {
                return false;
            }
            auto importDesc = getImportDesc(callSite->objName);
            if (abckitApi->inst.iGetOpcode(inst) != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDEXTERNALMODULEVAR)
            {
                return false;
            }
            if (abckitApi->import.iGetImportDescriptor(inst) != importDesc->i)
            {
                return false;
            }

            bool foundProp = false;
            abckitApi->inst.enumerateInstUsers(inst, [&](AbckitInst *user)
                                               {
                if (!foundProp && abckitApi->inst.iGetOpcode(user) == ABCKIT_ISA_API_DYNAMIC_OPCODE_LDOBJBYNAME) {
                    auto str = abckitApi->string.getInstName(user);
                    foundProp = str == callSite->propName;
                } 
                return true; });

            return foundProp;
        };

        void transform(InstStructType instStruct) override
        {
            auto apiInfo = this->param_->instApi;
            auto *inst = abc::getAs<AbckitInst>(instStruct);
            std::shared_ptr<ImportDescriptor> importDescriptor = getImportDesc(apiInfo->objName);
            auto file = abckitApi->function.functionGetFile(this->func_);
            auto *ldexternalmodulevar = abckitApi->isa.iCreateLdexternalmodulevar(this->graph_, importDescriptor->i);
            abckitApi->inst.iInsertBefore(ldexternalmodulevar, inst);

            auto *myAspect = abckitApi->isa.iCreateThrowUndefinedifholewithname(this->graph_, ldexternalmodulevar, abckitApi->string.createString(file, apiInfo->objName.c_str(), strlen(apiInfo->objName.c_str())));
            abckitApi->inst.iInsertAfter(myAspect, ldexternalmodulevar);

            auto *addBefore = abckitApi->isa.iCreateLdobjbyname(this->graph_, myAspect, abckitApi->string.createString(file, apiInfo->propName.c_str(), strlen(apiInfo->propName.c_str())));
            abckitApi->inst.iInsertAfter(addBefore, myAspect);

            auto *call = abckitApi->isa.iCreateCallthis0(this->graph_, addBefore, myAspect);
            abckitApi->inst.iInsertAfter(call, addBefore);
        }
    };

} // namespace task

#endif